import * as d3 from 'd3'
export class StackLineChart {
  data = ''
  divId = ''
  xLabel = ''
  yLabel = ''
  title = ''
  itemsName = []
  chart = {}
  color = d3.scaleOrdinal(d3.schemeCategory10)

  constructor (divId) {
    this.divId = divId
  }

  draw () {
    this.initChart()
    this.initAxis()
    this.drawLabel()
    this.drawLegend()
    this.drawStackLine()
  }
  // update () {
  //   this.drawLegend()
  //   this.drawStackLine()
  // }
  initChart () {
    this.chart.padding = {
      left: 50,
      right: 7,
      top: 20,
      bottom: 20
    }
    this.chart.divHeight = document.getElementById(this.divId).offsetHeight -
      this.chart.padding.top -
      this.chart.padding.bottom
    this.chart.divWidth = document.getElementById(this.divId).offsetWidth -
      this.chart.padding.left -
      this.chart.padding.right

    this.chart.svg = d3
      .select('#' + this.divId)
      .append('svg')
      .attr('width', this.chart.divWidth +
        this.chart.padding.left +
        this.chart.padding.right
      )
      .attr('height', this.chart.divHeight +
        this.chart.padding.top +
        this.chart.padding.bottom
      )
      .attr('class', 'svg_chart')
  }
  initAxis () {
    this.chart.xScale = d3.scalePoint()
      .domain(this.data.map(d => d.date))
      .range([this.chart.padding.left, this.chart.divWidth])

    this.chart.yScale = d3.scaleLinear()
      .domain([0, d3.max(this.data.map(d => d.RawCoal + d.CrudeOil + d.NaturalGas))])
      .range([this.chart.divHeight, this.chart.padding.top])

    this.chart.stack = d3.stack()
      .keys(this.itemsName)
      .offset(d3.stackOffsetNone)

    this.chart.xAxis = d3
      .axisBottom()
      .scale(this.chart.xScale)
      .ticks(this.data[0].length)
    //   .tickFormat((d) => 2015 + parseInt(d))
    this.chart.yAxis = d3.axisLeft().scale(this.chart.yScale)

    this.chart.svg
      .append('g')
      .attr('class', 'xAxis')
      .attr('transform', 'translate(0,' + this.chart.divHeight + ')')
      .call(this.chart.xAxis)

    this.chart.svg
      .append('g')
      .attr('class', 'yAxis')
      .attr('transform', 'translate(' + this.chart.padding.left + ')')
      .call(this.chart.yAxis)
  }
  drawStackLine () {
    this.drawArea()
    this.drawAreaStroke()
    this.drawPoints()
  }

  drawArea () {
    let scaleX = this.chart.xScale
    let scaleY = this.chart.yScale
    let data = this.data
    let t = d3.transition()
      .duration(1000)
      // .ease(d3.easeLinear)

    let area = this.chart.svg
      .selectAll('.area')
      .data(this.chart.stack(this.data))

    area.transition(t)
      .attrTween('d', areaTween)

    area.enter()
      .append('path')
      .attr('class', 'area')
      .style('fill', (_, i) => this.color(i))
      .style('stroke', (_, i) => this.color(i))
      .style('opacity', 0.4)
      // .style('stroke', 'black')
      // .style('stroke-width', 1)
      .transition(t)
      .attrTween('d', areaTween)

    function areaTween (_d) {
      if (!_d) {
        return 0
      }
      const gennrateArea = d3.area()
        .x(d => d[0])
        .y0(d => d[1])
        .y1(d => d[2])

      const pointX = data.map(d => scaleX(d.date))

      const pointY = _d.map(d => scaleY(d[0]))

      const pointY1 = _d.map(d => scaleY(d[1]))

      const interpolate = getAreaInterPolate(pointX, pointY, pointY1)

      let points = []

      return function (t) {
        points.push([interpolate.x(t), interpolate.y(t), interpolate.y1(t)])
        return gennrateArea(points)
      }
    }

    function getAreaInterPolate (pointX, pointY, pointY1) {
      const domain = d3.range(0, 1, 1 / (pointX.length - 1))
      domain.push(1)
      const interpolateX = d3.scaleQuantile()
        .domain(domain)
        .range(pointX)

      const interploateY = d3.scaleQuantile()
        .domain(domain)
        .range(pointY)

      const interPolateY1 = d3.scaleQuantile()
        .domain(domain)
        .range(pointY1)

      return {
        x: interpolateX,
        y: interploateY,
        y1: interPolateY1
      }
    }
  }

  drawPoints () {
    let t = d3.transition()
      .duration(1000)

    let points = this.chart.svg
      .selectAll('.group')
      .data(this.chart.stack(this.data))

    points.selectAll('.point')
      .transition(t)
      .attr('cx', d => this.chart.xScale(d.date))
      .attr('cy', d => this.chart.yScale(d[1]))

    points.enter()
      .append('g')
      .attr('class', 'group')
      .style('fill', 'white')
      .style('stroke', 'black')
      .selectAll('circle')
      .data(d => d)
      .enter()
      .append('circle')
      .attr('cx', d => this.chart.xScale(d.data.date))
      .attr('cy', d => this.chart.yScale(d[1]))
      .attr('r', 0)
      .transition(t)
      .attr('r', 5)

    // let pointsExit = points.exit()
    //   .transition(t)
    //   .remove()

    // pointsExit.selectAll('circle')
    //   .attr('r', 0)
  }

  drawAreaStroke () {
    let t = d3.transition()
      .duration(1000)

    this.chart.pathLine = d3.line()
      .x(d => this.chart.xScale(d.data.date))
      .y((d) => this.chart.yScale(d[1]))

    let lines = this.chart.svg
      .selectAll('.line')
      .data(this.chart.stack(this.data))

    lines.attr('d', this.chart.pathLine)
      .transition(t)

    lines.enter()
      .append('path')
      .attr('class', 'line')
      .attr('d', this.chart.pathLine)
      .style('stroke-dasharray', function (d) {
        return this.getTotalLength()
      })
      .style('stroke-dashoffset', function (d) {
        return this.getTotalLength()
      })
      .style('fill', 'none')
      .style('stroke', (_, i) => this.color(i))
      .transition(t)
      .style('stroke-dashoffset', 0)

    // let lineExit
    // lines.exit()
    //   .transition()
    //   .duration(1000)
    //   .style('stroke-dashoffset', function (d) {
    //     return this.getTotalLength()
    //   })
    //   .remove()
  }

  drawLabel () {
    // 标题
    this.chart.svg
      .append('text')
      .attr('x', this.chart.divWidth / 2 - this.title.length)
      .attr('y', this.chart.divHeight + this.chart.padding.bottom * 1.7)
      .text(this.title)
    // y轴
    this.chart.svg
      .append('text')
      .attr('x', this.chart.padding.left)
      .attr('y', this.chart.padding.top - 5)
      .text(this.yLabel)
    // x轴
    this.chart.svg
      .append('text')
      .attr('x', this.chart.divWidth + 5)
      .attr('y', this.chart.divHeight)
      .text(this.xLabel)
  }
  drawLegend () {
    let legendWidth = 15
    let legendHeight = 15
    let legends = this.chart.svg
      .selectAll('.legend')
      .data(this.itemsName)
    let legendEnter = legends.enter()
      .append('g')
      .attr('class', 'legend')

    legendEnter.append('rect')
      .attr('x', this.chart.divWidth/2 - 200)
      .attr('y', (d, i) => this.chart.padding.top + legendHeight * i +10)
      .attr('width', 0)
      .attr('height', legendHeight - 5)
      .style('fill', (d, i) => this.color(i))

    legendEnter.append('text')
      .attr('x', this.chart.divWidth/2 + legendWidth * 1.3 + - 200)
      .attr('y', (d, i) => this.chart.padding.top + legendHeight * i + legendHeight / 2 +10)
      .text(String)
      // .style('font-size', 1e-6)

    let legendUpdate = legendEnter.merge(legends)

    legendUpdate.select('rect')
      .transition()
      .duration(750)
      .attr('width', legendWidth)

    legendUpdate.select('text')
      .transition()
      .duration(750)
      .style('font-size', 10)

    // let legendExit = legends.exit()
    //   .transition()
    //   .duration(750)
    //   .remove()

    // legendExit.select('rect')
    //   .attr('width', 0)

    // legendExit.select('text')
    //   .style('stroke-opacity', 1e-6)
  }
}
